#include "apidecoding.h"
#include "mera.h"
#include "qrandom.h"

ApiDecoding::ApiDecoding()
{
    boofer = new BooferGH;
}

void ApiDecoding::add_to_boofer(double x, double y)
{
    boofer->add(x, y);
}

void ApiDecoding::clear_boofer()
{
    boofer->clear();
}

void ApiDecoding::lineal_pices_mistake()
{
    double *x_gh = new double[boofer->data_x.size()];
    double *y_gh = new double[boofer->data_y.size()];
    for(int i = 0; i < boofer->data_x.size(); i++)
    {
        x_gh[i] = boofer->data_x[i];
        y_gh[i] = boofer->data_y[i];
    }
    Approx *bin = new Approx();
    bin->lineal_pices(x_gh, y_gh, boofer->data_x.size());
    double mis = 0;
    for(double x = 0; x / 0.005 < 900; x += 0.005)
    {
        double y = sin(x);
        mis += abs(bin->calc_lineal_point(x) - y);
    }
    mis /= 900;
    cerr << mis * 100 << "    !!!!!!!!!!!!!!!!!!\n";
}

vector<double> ApiDecoding::least_squares_polynom(int max_pow)
{
    return approx::least_squares(&boofer->data_x, &boofer->data_y, max_pow);
}

void ApiDecoding::time_test()
{
    int size = 100000000;
    cerr << "prepare\n";
    double *x_points = new double[size];
    QRandomGenerator64 rd;
    for(int i = 0; i < size; i++)
    {
        double bug = std::generate_canonical<qreal, std::numeric_limits<qreal>::digits>(rd);
        x_points[i] = bug * 134 + 80;
    }
    double *x_gh = new double[boofer->data_x.size()];
    double *y_gh = new double[boofer->data_y.size()];
    for(int i = 0; i < boofer->data_x.size(); i++)
    {
        x_gh[i] = boofer->data_x[i];
        y_gh[i] = boofer->data_y[i];
    }
    cerr << "start\n";

    Approx *pol2 = new Approx();
    pol2->least_squares_arr(x_gh, y_gh, boofer->data_x.size(), 2);
    Approx *pol4 = new Approx();
    pol4->least_squares_arr(x_gh, y_gh, boofer->data_x.size(), 4);
    Approx *pol7 = new Approx();
    pol7->least_squares_arr(x_gh, y_gh, boofer->data_x.size(), 7);
    Approx *split = new Approx();
    split->lineal_pices(x_gh, y_gh, boofer->data_x.size());
    Approx *bin = new Approx();
    bin->lineal_pices(x_gh, y_gh, boofer->data_x.size());

    auto t1 = std::chrono::steady_clock::now();
    for(int i = 0; i < size; i++)
    {
        pol2->calc_polynom_point(x_points[i]);
    }
    auto t2 = std::chrono::steady_clock::now() - t1;
    qDebug() << "pol2 time " << std::chrono::duration_cast<std::chrono::milliseconds>(t2).count() << " ms";

    t1 = std::chrono::steady_clock::now();
    for(int i = 0; i < size; i++)
    {
        pol4->calc_polynom_point(x_points[i]);
    }
    t2 = std::chrono::steady_clock::now() - t1;
    qDebug() << "pol4 time " << std::chrono::duration_cast<std::chrono::milliseconds>(t2).count() << " ms";

    t1 = std::chrono::steady_clock::now();
    for(int i = 0; i < size; i++)
    {
        pol7->calc_polynom_point(x_points[i]);
    }
    t2 = std::chrono::steady_clock::now() - t1;
    qDebug() << "pol7 time " << std::chrono::duration_cast<std::chrono::milliseconds>(t2).count() << " ms";

    t1 = std::chrono::steady_clock::now();
    for(int i = 0; i < size; i++)
    {
        split->calc_split_lineal_point(x_points[i]);
    }
    t2 = std::chrono::steady_clock::now() - t1;
    qDebug() << "split time " << std::chrono::duration_cast<std::chrono::milliseconds>(t2).count() << " ms";

    t1 = std::chrono::steady_clock::now();
    for(int i = 0; i < size; i++)
    {
        bin->calc_lineal_point(x_points[i]);
    }
    t2 = std::chrono::steady_clock::now() - t1;
    qDebug() << "bin time " << std::chrono::duration_cast<std::chrono::milliseconds>(t2).count() << " ms";

    delete[] x_points;
    delete[] x_gh;
    delete[] y_gh;
    cerr << "end\n";
}

vector<double> ApiDecoding::legendre_approx_polynom(int max_pow)
{
    return approx::legendre_approx(&boofer->data_x, &boofer->data_y, max_pow);
}

vector<double> ApiDecoding::legendre_with_mistake(double mistake)
{
    vector<double> res;
    for(unsigned int i = 1; i <= boofer->data_x.size() and i <= 7; i++)
    {
        res = approx::legendre_approx(&boofer->data_x, &boofer->data_y, i);
        if(approx_mistake(&res) <= mistake)
            return res;
    }
    return res;
}

vector<double> ApiDecoding::least_squares_with_mistake(double mistake)
{
    vector<double> res;
    for(unsigned int i = 1; i <= boofer->data_x.size() and i <= 7; i++)
    {
        res = approx::least_squares(&boofer->data_x, &boofer->data_y, i);
        if(approx_mistake(&res) <= mistake)
            return res;
    }
    return res;
}

double ApiDecoding::squared_deviation()
{
    return approx::squared_deviation(&boofer->data_y);
}

double ApiDecoding::correlation(vector<double> *polynom_values)
{
    return approx::correlation(&boofer->data_x, &boofer->data_y, polynom_values);
}

double ApiDecoding::approx_mistake(vector<double> *polynom_values)
{
    return approx::approx_mistake(&boofer->data_x, &boofer->data_y, polynom_values);
}

vector<double> ApiDecoding::calc_polynom(vector<double> *polynom_values, vector<double> *x_values)
{
    return approx::calc_polynom_func(polynom_values, x_values);
}
